﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Portal.FileSystemData;
using System.IO;
using System.Threading;

namespace Portal.Modules.ImageBrowser
{
  /// <summary>
  /// Summary description for CacheAgent
  /// </summary>
  public class CacheAgent
  {
    DataAccessor _dataAccessor;
    ImageUtility _imageUtility;



    public CacheAgent(DataAccessor dataAccess)
    {
      _dataAccessor = dataAccess;
      _imageUtility = new ImageUtility(_dataAccessor.Config);
    }


    /// <summary>
    /// Makes sure that the cache file for the image objects exists and returns the url.
    /// </summary>
    /// <param name="fileSystemObj">The file to access</param>
    /// <returns>The url to the cache file</returns>
    public string GetThumbnailImageUrl(FileSystemWrapper fileSystemObj)
    {
      if (fileSystemObj == null)
        throw new ArgumentNullException("fileSystemObj");

      string imageUrl = string.Empty;
      if (fileSystemObj.IsDirectory)
      {
        string dirImagePath = Path.Combine(fileSystemObj.PhysicalPath, "_dirimage.jpg");
        if (!File.Exists(dirImagePath))
        {
          DirectoryWrapper dir = fileSystemObj as DirectoryWrapper;
          if (dir.FileCount > 0)
            dirImagePath = Path.Combine(fileSystemObj.PhysicalPath, dir.Files[0].Name);
          else
            return "~/PortalImages/folder.gif";
        }

        string thumbPath = GetThumbnailCachePath(Path.Combine(fileSystemObj.PhysicalPathRelative, "_dirimage.jpg"));

        // Prevent multiple updates at the same time.
        lock (fileSystemObj)
        {
          if (!File.Exists(thumbPath))
            _imageUtility.CreateImage(dirImagePath, thumbPath, _dataAccessor.Config.ThumbCfg, _dataAccessor.Config.ThumbCfg.HasShadow);
          imageUrl = GetThumbnailVirtualCachePath(fileSystemObj.VirtualPath + "_dirimage.jpg", true);
        }
      }
      else
      {
        string thumbPath = GetThumbnailCachePath(fileSystemObj);

        // Prevent multiple updates at the same time.
        lock (fileSystemObj)
        {
          if (!File.Exists(thumbPath))
            _imageUtility.CreateImage(fileSystemObj.PhysicalPath, thumbPath, _dataAccessor.Config.ThumbCfg, _dataAccessor.Config.ThumbCfg.HasShadow);
        }

        imageUrl = GetThumbnailVirtualCachePath(fileSystemObj, true);
      }
      return imageUrl;
    }

    private void UpdateThumbnail(FileSystemWrapper fileSystemObj)
    {
      GetThumbnailImageUrl(fileSystemObj);
    }

    /// <summary>
    /// Updates the cache with the thumbnail pictures. This process is asynchronous.
    /// </summary>
    public void UpdateThumbnailCache()
    {
      string thumbPath = Path.Combine(_dataAccessor.Config.PicturePhysicalPath, "_thumbs");
      var updater = new CacheUpdater(_dataAccessor.ModuleDocument.ModuleRef + "thumb", UpdateThumbnail);
      updater.UpdateCache(thumbPath, _dataAccessor.RootDirectory);
    }

    /// <summary>
    /// Returns the absolute physical path of the thumbnail cache file.
    /// </summary>
    /// <returns></returns>
    public string GetThumbnailCachePath(FileSystemWrapper fileSystemObj)
    {
      if (fileSystemObj.IsDirectory)
        throw new InvalidOperationException("Not allowed for directory");

      return GetThumbnailCachePath(fileSystemObj.PhysicalPathRelative);
    }

    public string GetThumbnailCachePath(string physicalPathRelative)
    {
      return Path.Combine(Path.Combine(_dataAccessor.Config.PicturePhysicalPath, "_thumbs"), physicalPathRelative);
    }


    /// <summary>
    /// Returns the relative virtual path of the thumbnail cache file.
    /// </summary>
    /// <returns></returns>
    public string GetThumbnailVirtualCachePath(FileSystemWrapper fileSystemObj, bool makeCfgVersionUnique)
    {
      return GetThumbnailVirtualCachePath(fileSystemObj.VirtualPath, makeCfgVersionUnique);
    }

    public string GetThumbnailVirtualCachePath(string virtualPath, bool makeCfgVersionUnique)
    {
      string path = VirtualPathUtility.Combine(_dataAccessor.Config.PictureVirtualPath, "_thumbs");
      path = VirtualPathUtility.Combine(VirtualPathUtility.AppendTrailingSlash(path), virtualPath);
      if (makeCfgVersionUnique)
      {
        // Prevent caching, when the configuration has changed.
        path += "?v=" + _dataAccessor.Config.ConfigVersion;
      }
      return path;
    }


    /// <summary>
    /// Returns the absolute physical path of the preview cache file.
    /// </summary>
    /// <returns></returns>
    public string GetPreviewCachePath(FileSystemWrapper fileWrapper)
    {
      return GetPreviewCachePath(fileWrapper.PhysicalPathRelative);
    }


    public string GetPreviewCachePath(string physicalPathRelative)
    {
      return Path.Combine(Path.Combine(_dataAccessor.Config.PicturePhysicalPath, "_preview"), physicalPathRelative);
    }

    /// <summary>
    /// Returns the relative virtual path of the preview cache file.
    /// </summary>
    /// <returns></returns>
    public string GetPreviewVirtualCachePath(FileSystemWrapper fileWrapper, bool makeCfgVersionUnique)
    {
      return GetPreviewVirtualCachePath(fileWrapper.VirtualPath, makeCfgVersionUnique);
    }

    /// <summary>
    /// Returns the relative virtual path of the preview cache file.
    /// </summary>
    /// <returns></returns>
    public string GetPreviewVirtualCachePath(string virtualPath, bool makeCfgVersionUnique)
    {
      string path = VirtualPathUtility.Combine(_dataAccessor.Config.PictureVirtualPath, "_preview");
      path = VirtualPathUtility.Combine(VirtualPathUtility.AppendTrailingSlash(path), virtualPath);
      if (makeCfgVersionUnique)
      {
        // Prevent caching, when the configuration has changed.
        path += "?v=" + _dataAccessor.Config.ConfigVersion;
      }
      return path;
    }

    /// <summary>
    /// Makes sure that the cache file for the image objects exists and returns the url.
    /// </summary>
    /// <param name="fileWrap">The file to access</param>
    /// <returns>The url to the cache file</returns>
    public string GetPreviewImageUrl(FileWrapper fileWrap)
    {
      string previewCachePath = GetPreviewCachePath(fileWrap);
      if (!File.Exists(previewCachePath))
        _imageUtility.CreateImage(fileWrap.PhysicalPath, previewCachePath, _dataAccessor.Config.PreviewCfg, false);
      return GetPreviewVirtualCachePath(fileWrap, true);
    }

    private void UpdatePreview(FileSystemWrapper fileSystemObj)
    {
      var fileWrap = fileSystemObj as FileWrapper;
      if (fileWrap != null)
        GetPreviewImageUrl(fileWrap);
    }

    public void UpatePreviewCache(bool bUpdateShadowToo)
    {
      string previewPath = Path.Combine(_dataAccessor.Config.PicturePhysicalPath, "_preview");
      var updater = new CacheUpdater(_dataAccessor.ModuleDocument.ModuleRef + "preview", UpdatePreview);
      updater.UpdateCache(previewPath, _dataAccessor.RootDirectory);
    }

    /// <summary>
    /// Returns the physical path of the shadow files.
    /// </summary>
    public string PreviewShadowPath
    {
      get 
      {
        return Path.Combine(_dataAccessor.Config.PicturePhysicalPath, "_shadow");
      }
    }

    /// <summary>
    /// Returns the virtual path of the shadow files.
    /// </summary>
    public string PreviewVirtualShadowPath
    {
      get
      {
        return VirtualPathUtility.ToAbsolute(VirtualPathUtility.Combine(_dataAccessor.Config.PictureVirtualPath, "_shadow/"));
      }
    }

    public void UpdatePreviewShadowParts()
    {
      _imageUtility.CreateShadowParts(_dataAccessor.Config.PreviewCfg, PreviewShadowPath);
    }
  }
}